package edu.gmu.middleware;

import edu.gmu.streams.BlockInputStream;
import edu.gmu.streams.ByteBufferInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * The UnmarshalerImpl object will take a byte[] and
 * unmarshal it into a Message.  The unmarshaling expects the header
 * and will unmarshal it first before the body of the Message.
 * 
 * @author  James H. Pope
 * @version $Revision:$ $Date:$
 */
public class UnmarshalerImpl implements Unmarshaler
{
    /**
     * Creates a new UnmarshalerImpl default values.
     */
    public UnmarshalerImpl()
    {
        
    }

    /**
     * Unmarshals the specified input using the specified header 
     * into a Message object.  The specific type of payload in 
     * the message object is determined by the registration type.
     * @param header
     * @param in
     * @param messageBinding
     * @return message
     * @throws IOException if the unmashaling process was not successful
     * @throws IllegalStateException if no binding for id in registry
     */
    public Message unmarshal(   Header header,
                                ByteBuffer in,
                                MessageBinding messageBinding ) throws IOException
    {
        /*
         * Unmarshal the header - we need to know byte order and message id
         */
        header.unmarshal(in);
        //System.out.println( "header.unmarshal="+Header.toString(in) );
        
        // First set correct endian order
        if( header.getEndianFlag() == EndianFlag.LITTLE_ENDIAN )
        {
            in.order( ByteOrder.LITTLE_ENDIAN );
        }
        else
        {
            in.order( ByteOrder.BIG_ENDIAN );
        }
        
        /*
         * Header is already unmarshaled - now figure out payload
         */
        
        BlockInputStream inputStream = new ByteBufferInputStream( in );
        

        // Resolver the id -> class type
        int topic = header.getTopic();
        Class parameterType = messageBinding.getBoundClass();
        Message message = null;
        try
        {
            /*
             * Create message object and "deserialize" i.e. unmarshal.
             */
            Object obj = parameterType.newInstance();
            if( obj != null && obj instanceof Message )
            {
                message = (Message) obj;

                //Read message body
                message.unmarshal( inputStream );
            }
        }
        catch (Exception ex)
        {
            String s = "Exception while instantiating/unmarshaling topic "+topic;
            IllegalStateException e = new IllegalStateException(s, ex);
            throw e;
        }

        return message;
    }
}
